﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Threading;
using Zero.Common;

namespace Zero.Service
{
    /// <summary>
    /// WCF service for communication of frontend and backend.
    /// </summary>
    public class Service : IService
    {
        private static readonly CompositionContainer Container;

        static Service()
        {
            Container = new CompositionContainer(
                new AggregateCatalog(
                    AppDomain.CurrentDomain.GetAssemblies().Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()
                    )
                );
        }

        /// <summary>
        /// Implementation of <see cref="IService.ProcessObject"/>
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public TransportObject ProcessObject(TransportObject request)
        {
            Thread.Sleep(150);

            object response = GetBackend().Process(request.Data);
            return new TransportObject(response);
        }

        /// <summary>
        /// Resolves backend to process requests.
        /// </summary>
        /// <returns></returns>
        protected virtual IBackend GetBackend()
        {
            var x = GetInstance(typeof (IBackend), null);
            return (IBackend) x;
        }

        /// <summary>
        /// Basic IoC functionality.
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        protected object GetInstance(Type serviceType, string key)
        {
            string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
            var exports = Container.GetExportedValues<object>(contract);

            if (exports.Count() > 0)
                return exports.First();

            throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
        }
    }
}
